-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bech32 orderbook #656
Bech32 orderbook #656
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we remove this part? 😊
Good job jules!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fantastic, thanks!
good choice to name it for example sw0absoffer
, this allows easy upgrade to future segwit version, like taproot.
Exactly what I had in mind! |
I've taken a closer look at this, and I am now quite confident that I am correct here. 78bc162 is a small commit to correct this elsewhere in the codebase. |
Looking good so far, although I'm only kind of half way through reviewing. Thanks for diving in, it will be great to have another person with all-around knowledge of how this works :)
For sure, I agree with this choice. Note that of course any name would work just as well to do a "soft fork" style upgrade, just as we did previously (absoffer -> swabsoffer). And indeed we don't need to constantly lengthen these names :) Testing with Re: the script verify flags, that indeed looks like a necessary correction (in case it confuses anyone, not having all the right script verify flags has not been a cause for any failure in transactions up to now, because an incomplete verification doesn't prevent transactions going through, and there is of course no danger with the functionality as is, because if we count as 'valid' a tx that isn't valid, it just results in a failed transaction push onto the network; not dangerous with coinjoin). I wonder if @dgpv could explain the necessity for P2SH as well as WITNESS for WITNESS-only case, as I read the explanation and couldn't understand it. *** There is a detail about running manual coinjoins: |
I'm afraid that I would not be able to explain it either without taking the effort to dig into Bitcoin Core source and commit history. The code in python-bitcointx just mirrors the code in Bitcoin Core (https://github.com/bitcoin/bitcoin/blob/bf0dc356ac4a2bdeda1908af021dea2de0dfb35a/src/script/interpreter.cpp#L1646-L1654). Core developers who was involved with BIP141 code might know better. It seems to me that this requirement is an artifact of how Core code is structured, and since python-bitcointx aims to mirror this code quite close, the same requirement is present. |
flags = set([SCRIPT_VERIFY_STRICTENC]) | ||
# np2wkh and p2wkh cases each require both flags | ||
# See bitcointx/core/scripteval.py:1255 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to a commit in case line numbers shift.
jmclient/jmclient/configure.py
Outdated
# currently supported in Joinmarket coinjoins. Only set to "true" | ||
# if specifically advised to do so. | ||
native = false | ||
# Use native segwit (bech32) wallet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a line to the comment to explain what happens if you set it to False (perhaps something like "if you set this to 'false', p2sh wrapped segwit (p2sh-p2wpkh) will be used when generating a new wallet; note that the default Joinmarket pit does not support this, and also note that pre-existing wallets do not change their type." ... well it's tricky to cover every detail, but these points seem like the most obvious ones to note.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note that the default Joinmarket pit does not support this
Making sure we are on the same page, do you mean that the default joinmarket pit does not support native segwit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AdamISZ friendly ping!
jmclient/jmclient/maker.py
Outdated
@@ -171,8 +171,7 @@ def on_tx_received(self, nick, tx_from_taker, offerinfo): | |||
# unchanged as (sig, pub). | |||
try: | |||
sig, pub = [a for a in iter(tx.wit.vtxinwit[index].scriptWitness)] | |||
scriptCode = btc.pubkey_to_p2wpkh_script(pub) | |||
sigmsg = btc.CScript([sig]) + btc.CScript(pub) + scriptCode | |||
sigmsg = btc.CScript([sig]) + btc.CScript(pub) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just stating the relatively obvious here: this means new code cannot do Joinmarket coinjoins with p2sh. I think it's the right decision, but in principle, we could also do a check on the wallet type and then change the sig msg to be one of these two syntaxes.
The reason I think it's the right choice is (a) keeping logic simpler and (b) if we have an upgrade like this, we do want to strongly encourage people to shift over. There are counterarguments though, I don't know if anyone wants to make that.
Given that decision though, this is the right code change, of course.
This was wrong, see Taker.on_sig()
changes as to why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case I plan to continue running P2SH yg for some time (as I previously did with P2PKH), instead of sweeping everything to a new native segwit bech32 wallet, but maybe it's ok to continue using v0.6.x for that. Downside - unability to do P2SH BIP78 payjoins from such wallet in case that is what receiving side is supporting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just stating the relatively obvious here: this means new code cannot do Joinmarket coinjoins with p2sh.
@AdamISZ I'm assuming that you mean that p2sh is nested p2wkh. It seems to me that those changes, in conjunction with those on the taker side, should still support p2sh. What I've done is I've brought the creation of scriptCode
entirely on the taker side. These changes depend entirely on the assumption that p2sh is np2wkh as far as coinjoins are concerned. I'd encourage people to take a look at the taker.py
changes to understand my reasoning here.
Downside - unability to do P2SH BIP78 payjoins from such wallet in case that is what receiving side is supporting.
@kristapsk If my reasoning is correct above, then I think P2SH BIP78 payjoins will still be possible with these changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's the right decision, but in principle, we could also do a check on the wallet type and then change the sig msg to be one of these two syntaxes.
I actually think this would improve the code here and make it cleaner! I'm thinking of a simple if statement conditioned on the wallet type to set the correct syntax for sigmsg
. This assumes that all the inputs from a single maker will be of the same type. If people like this, I'll make this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downside - unability to do P2SH BIP78 payjoins from such wallet in case that is what receiving side is supporting.
Well, first, I think we should release 0.7.0 without this PR and second you could still do BIP78 payjoins with this PR included, just as today you can do BIP78 payjoins with native wallets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just stating the relatively obvious here: this means new code cannot do Joinmarket coinjoins with p2sh.
@AdamISZ I'm assuming that you mean that p2sh is nested p2wkh. It seems to me that those changes, in conjunction with those on the taker side, should still support p2sh. What I've done is I've brought the creation of
scriptCode
entirely on the taker side. These changes depend entirely on the assumption that p2sh is np2wkh as far as coinjoins are concerned. I'd encourage people to take a look at thetaker.py
changes to understand my reasoning here.
I wrote this comment before reading how you had changed Taker.on_sig()
(see my extended comment on that below). It was not correct, so you can ignore this comment. (uh second edit:
so this is the maker code - if this maker wanted to do p2sh coinjoins it would want to support pre-"soft fork" takers, which will only accept three arguments. So yes it is probably better to flag on the wallet type).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think this would improve the code here and make it cleaner! I'm thinking of a simple if statement conditioned on the wallet type to set the correct syntax for
sigmsg
. This assumes that all the inputs from a single maker will be of the same type. If people like this, I'll make this change.
So as per above, I agree this is probably the best. It doesn't hurt to add this functionality, even if we are defaulting new makers to bech32 (after this PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could still do BIP78 payjoins with this PR included
My comment was about v0.6.x, where BIP78 payjoin support is not included.
There is a problem here:
estimate_tx_fee in the main code (not testing), you'll see that the calls specify tx_type = wallet_service.get_tx_type() to figure out an estimate depending on scriptPubKey type, so we need to make that happen here too (to be clear, the usage there in sendpayment is very much a "first near-total guess" but all the same).
Edit: it's also in tumbler.py, same thing. |
jmclient/jmclient/taker.py
Outdated
elif len(sig_deserialized) == 3: | ||
ver_sig, ver_pub, scriptCode = sig_deserialized | ||
ver_sig, ver_pub, trash = sig_deserialized |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. First, it's traditional to use _
for unused return values, like a, b, _ = func_that_returns_a_tuple()
... I suspect for linting reasons it's preferable, though not important.
That we formerly had that third item is interesting - it was mostly being used as a flag - thus the maker is clearly identifying he is providing a wrapped segwit signature - but secondarily as a sanity check on the redeemScript. But of course it technically wasn't necessary for that secondary reason because the pubkey is provided and you could reconstruct it from that; even though that represents an assumption, it's a fine one to make (anything else is unrecognized, which is already true for anything unexpected).
Here you've used the python-bitcointx functions to make the processing cleaner - take the sig and pub data and check the type of the scriptPubKey, then process it based on the assumption that it is one of those three types (so as before it assumes that any p2sh is p2sh-p2wpkh and fails otherwise.
There is an argument of course (a good one really) for generalising further so that we can accept any old inputs. It complicates the bot messaging protocol but we probably should have done it from day one, it's just our bitcoin backend library wasn't powerful enough (or safe enough I guess); we can have the bots just send full blown PSBTs (modulo the bandwidth, ouch), or just stripped down: scriptSig and scriptPubKey in bitcoin serialization. But that's for another day.
I think what you have in this function is good.
Yes thanks that makes sense, appreciate the explanation. Since I was curious I pinged #bitcoin on IRC, harding gave an answer:
Probably requires a bit more reading around Core's script validation code to understand fully. |
Yeah just an .md file in docs and the rest will go in release notes. This could be a good starting point (and sidenote, we should already have removed that, it's way old). |
Just some commentary on something most people might not think of: PoDLEs are hashes of the shifted pubkey corresponding to the pubkey which forms the basis of the scriptPubKey of a utxo which the taker is referring to and signing against, effectively, with the podle. The assumption the maker makes is that the type of scriptpubkey offered is the same as his own wallet, see: joinmarket-clientserver/jmclient/jmclient/maker.py Lines 91 to 93 in fbf6fb0
So clearly this is fine in general; in almost all cases we generate podles from utxos actually in the wallet concerned, so they have to be the right type for that coinjoin. The only exception is "external" commitments (podles) which can be stored in a file as explained here (which is linked under 'funding the wallet' in the usage guide). I'm not sure anything can/should realistically be done to address this, since this feature appears to be largely unused. Perhaps we just drop a note somewhere (and at the same time move that commitments explainer page into docs/). |
This should fix all the issues / suggestions raised so far. I am confident we can deploy some testnet instances of this PR for testing. On regtest, the only thing of note I haven't been able to test thus far is the I'll add a documentation commit for the migration process soon. EDIT: There is a small detail I need to update please wait before reviewing. |
Ok now I think this is ready. Bear in mind that if you run the test suite with I now have been able to run |
Problem in ob-watcher cropping up in testing:
is picking up 4 rather than 2 different order types, which is causing a database query to throw an exception (see the SQL in For now a simple fix to stop the error: change to
But I would suggest a fuller fix is to remove entirely the non-segwit offerbook feature and replace it with 'legacy segwit', which will mean several changes to the ob-watcher and its html. To be clear I don't think this is a blocking issue at all. |
3d6e325 should fix this. That being said I didn't take the time yet to faithfully reproduce the error by creating multiple types of offers at the same time with Let me know if you'd like me to squash that latest commit. EDIT: The big picture: The |
I think pre-segwit legacy orderbook could be dropped from ob-watcher entirely, it's always empty last few times I checked, don't think anybody still uses it. Also, it's not supported outside ob-watcher by JM-CS. |
@AdamISZ Thoughts on this? I think I agree with Kristaps here... |
@AdamISZ @kristapsk I went ahead and removed the pre-segwit legacy orderbook as requested. |
I don't agree with it being beyond the scope. It's bad for a PR to break tests, as part of the point of tests is so that when different people work on a project they don't accidentally break other parts of the project. |
I think the PR doesn't break tests, as it changes the default setting of native to And having the test suite pass whether the setting is |
I have an error when running the yield generator since the last rebase. Seems like some nasty loop repeating:
Settings are as per: #632 (comment) (was working previously) running the YG:
EDIT tested @ this commit: |
Test suite is passing as of 98e838c but note, as per comments earlier in the thread, While this change was trivial, there is something interesting behind it: the |
thanks for the report; could you give an exact commit, since there were several small changes today? |
If you're running on latest commit, this is no longer correct, see last sentence of #656 (comment) |
@openoms as well as the other questions above, also: is the error condition repeatable? |
Test suite now passes for me too. |
Updated to the latest commit in this PR (d21f30 update Yieldgen docs for offer type) and this issue still persists. With
Also the
might be related? |
@openoms reproduced. looking at it today. |
@openoms so far cannot reproduce, but I tested on regtest with this:
|
@openoms i also tested on mainnet, seems to work fine. not sure what's happening with you there. |
I think we are ready for squash (of my additions, @Jules23 commits can stay as is imo) and merge (ob-watcher problem above is due to blocked testnet IRC channel, so not relevant here). Except, we need to update references in the documentation. This is not critical as long as the basic instructions are all correct for the default wallet type; so I'm not inclined e.g. to change every example screenshot for the GUI, yet. and I will delete the old files:
... because they both refer to years-old upgrades and will cause a bunch of confusion to current users, if they read them. While I'm doing this if anyone wants to sanity check by running a bot or two on mainnet that would be great :) |
IRC server is fixed. My testnet offer is ready for testing. |
b1151d3 is I believe a complete update of the docs to account for the new default wallet type (plus a small number of very minor unrelated updates as I was reading through it). Please let me know if I missed something. |
Not sure it's related with this PR, but tried doing CJ as a taker in testnet and it kinda hanged up.
Then, when I pressed Ctrl+C:
|
Did the same testnet test with JoinMarketQt, it succeeded. |
@kristapsk on regtest, there's a weird/annoying bug where the prompt 'do you want to send?' doesn't show up, but it's still waiting for you to type 'y' or 'n'. I can't remember if it also applies to testnet, but I think it does (I can check; if you're confused, it's something to do with twisted logging, which is switched off for mainnet). Either way, we don't get this on mainnet. |
@kristapsk i can confirm that i can reproduce (no 'builtinserror' on ctrl-c but basically) and stop the error by removing this: joinmarket-clientserver/scripts/sendpayment.py Lines 314 to 315 in b1151d3
Pretty sure this is not in any way related to the PR |
@AdamISZ Can confirm, removing these lines solves the issue. Do we need that twisted logging on testnet? Maybe can be removed? |
Yeah, can be removed. I can add it for certain tests if i need it. |
* yg scripts set reloffer/absoffer only: Prior to this commit, the yield generator user level scripts required the user to specify offer types depending on the wallet, but only 'rel/abs' distinction is user choice; the other element (native segwit, p2sh or p2pkh) must be defined by the wallet, so we now call `wallet.get_txtype()` to translate from reloffer/absoffer to sw0.. etc. * Taker chooses nversion, nlocktime per wallet type: Takers who are still using p2sh-p2wpkh wallets will not want to flag their transactions with different tx metadata than previous versions that are still running, so we check the `get_txtype()` output to decide which nVersion and nLockTime to use. Also, the SNICKER locktime is reverted to zero as according to draft spec. * change offer type in test_coinjoin * update docs for bech32 wallets
Squashed my changes down to one commit, merged to master. Feel free to publicise that widely. If you do that, also make sure to let people know about 'reloffer' in the script settings, as well as the obvious one about wallet type. |
Great! Thank you so much @AdamISZ @kristapsk @openoms for getting this over the finish line! |
This is wonderful - fantastic work - thanks a lot to all devs & reviewers - eager to see how the bootstrapping of this new orderbook will go... |
Since JoinMarket-Org/joinmarket-clientserver#656 JoinMarket supports bech32 addresses also for CoinJoins, with a dedicated orderbook.
Aims to create an orderbook for native segwit v0 addresses. See #632 for more discussion.
Notes on 9242200:
SCRIPT_VERIFY_P2SH
and theSCRIPT_VERIFY_WITNESS
flags toVerifyScript
need to be set. I've made the correction just inverify_tx_input
but let me know if this is wrong.Note on 0ae3c9e: For now, I have left the defaults for the maker's fake offer and
yg-privacyenhanced.py
on nested segwit.For testing, I am at the point where the test suite passes. I have not yet tried to run the various scripts with the new offer types, but I thought I'd open this to give an update on where the code is right now. Let me know what additional testing we can do before merging into master.
EDIT: I also still need to do a write-up on the migration process.